import Sortable from 'sortablejs';
import QTable from '@/components/base-ui/base-table/index.vue';
import { flattenArray, getTime, getDom, isArray } from '@/utils';
import type { MaterialChooseVO } from '@/api/modeling/bom/model/type';

export default (tableRef: Ref<InstanceType<typeof QTable>>) => {
    /**
     * 记录当前拖拽行信息
     */
    type TableData = MaterialChooseVO & anyObj;
    let hasChildren = false;
    let activeRows: TableData[] = []; // 记录拖拽活动元素，用于最终更新表格数据匹配
    const recordRow = (row: TableData) => {
        draggedItem.value = row;

        // 记录当前行对象是否存在子级
        hasChildren = !!row.children;

        // 将表格数据拍平
        activeRows = flattenArray(tableRef.value.tableData);
    };

    /**
     * 点击拖拽初始化 sorTable 实例
     */
    const draggedItem = ref<TableData | null>(null);
    const tableKey = ref(getTime());
    let sortable: Sortable | null = null; // sortable对象

    const initDrag = () => {
        if (sortable && sortable.el) {
            sortable.destroy(); // 销毁拖拽实例
        }

        tableKey.value = getTime(); // 用于重新刷新表格数据
        nextTick(() => {
            initDragInstance();
        });
    };

    /**
     * 初始化实例
     */
    const initDragInstance = () => {
        const tBody = getDom('#q-table .el-table__body tbody') as HTMLElement;

        sortable = Sortable.create(tBody, {
            handle: '.drag-handle', // 可执行拖拽的元素类名
            ghostClass: 'drag-ghost',
            animation: 200,
            onStart: () => {
                if (hasChildren) {
                    tableRef.value.tableToggleRowExpansion(draggedItem.value!, false); // 折叠当前拖拽元素
                }
            },
            onEnd: ({ oldIndex, newIndex }) => {
                const oldRow = activeRows[oldIndex!]; // 当前拖拽元素索引
                const newRow = activeRows[newIndex!]; // 被拖拽后索引
                const tableData = tableRef.value.tableData as TableData[];

                if (oldRow.id === newRow.id) return;
                if (oldRow.level === newRow.level && oldRow.parentId === newRow.parentId) {
                    // 同级拖拽
                    if (oldRow.level === 1 && newRow.level === 1) {
                        // 拖拽元素与所放置元素 BOM 层级都为 1
                        const draggedIndex = getIndex(tableData, oldRow.id!); // 通过拖拽活动数据匹配出真实表格数据中所处位置
                        const relatedIndex = getIndex(tableData, newRow.id!); // 通过放置元素数据匹配出真实表格数据中所处位置

                        const [movedItem] = tableData.splice(draggedIndex, 1);
                        if (oldIndex! > newIndex! || !newRow.children || !newRow.children.length) {
                            // 从下至上拖拽或者从上之下拖拽中拖放元素没有子级
                            tableData.splice(relatedIndex, 0, movedItem);
                        } else {
                            // 从上至下拖拽
                            const currentRow = findDataById(activeRows, newRow.id!);
                            movedItem.parentId = currentRow!.id;
                            movedItem.level++;
                            recursiveSetLevel(movedItem.children, movedItem.level); // 递归设置当前及子级的 level
                            currentRow!.children.splice(0, 0, movedItem);
                        }
                    } else {
                        // 子级同级之间拖拽
                        const parentRow = findDataById(activeRows, newRow.parentId); // 递归遍历查找拖动元素的父级数据
                        const children = parentRow!.children; // 当前拖拽所在树列表
                        const draggedIndex = getIndex(children, oldRow.id!); // 拖拽索引
                        const relatedIndex = getIndex(children, newRow.id!); // 拖放索引
                        const relatedRow = children[relatedIndex]!; // 拖放数据

                        const [movedItem] = children.splice(draggedIndex, 1);
                        if (oldIndex! > newIndex! || !newRow.children) {
                            // 从下至上拖拽或者从上之下拖拽中拖放元素没有子级
                            children.splice(relatedIndex, 0, movedItem);
                        } else {
                            // 从上至下拖拽
                            movedItem.parentId = relatedRow.id;
                            movedItem.level++;
                            relatedRow.children.splice(0, 0, movedItem);
                        }
                    }
                } else {
                    // 跨级拖拽
                    if (oldRow.level === 1) {
                        const parentRow = findDataById(activeRows, newRow.parentId); // 递归遍历查找拖动元素的父级数据
                        const children = parentRow!.children;
                        const draggedIndex = getIndex(tableData, oldRow.id!); // 拖拽索引
                        const relatedIndex = getIndex(children, newRow.id!); // 拖放索引

                        const [movedItem] = tableData.splice(draggedIndex, 1);
                        movedItem.level = children[relatedIndex].level;
                        movedItem.parentId = children[relatedIndex].parentId;
                        recursiveSetLevel(movedItem.children, movedItem.level); // 递归设置当前及子级的 level
                        if (oldIndex! > newIndex!) {
                            // 从下至上拖拽
                            children.splice(relatedIndex, 0, movedItem);
                        } else {
                            // 从上至下拖拽
                            children.splice(relatedIndex + 1, 0, movedItem);
                        }
                    } else {
                        const draggedParentRow = findDataById(activeRows, oldRow.parentId);
                        const children = draggedParentRow!.children;
                        const draggedIndex = getIndex(children, oldRow.id!); // 拖拽索引

                        const [movedItem] = children.splice(draggedIndex, 1);

                        if (newRow.level === 1) {
                            const relatedIndex = getIndex(tableData, newRow.id!); // 拖放索引
                            movedItem.level = 1;
                            delete movedItem.parentId;
                            recursiveSetLevel(movedItem.children, movedItem.level); // 递归设置当前及子级的 level
                            tableData.splice(relatedIndex, 0, movedItem);
                        } else {
                            const relatedParentRow = findDataById(activeRows, newRow.parentId);
                            const relatedChild = relatedParentRow!.children;
                            const relatedIndex = getIndex(relatedChild, newRow.id!); // 拖放索引

                            movedItem.level = relatedChild[relatedIndex].level;
                            movedItem.parentId = relatedChild[relatedIndex].parentId;
                            recursiveSetLevel(movedItem.children, movedItem.level); // 递归设置当前及子级的 level
                            if (oldIndex! > newIndex!) {
                                // 从下至上拖拽
                                relatedChild.splice(relatedIndex, 0, movedItem);
                            } else {
                                // 从上至下拖拽
                                relatedChild.splice(relatedIndex + 1, 0, movedItem);
                            }
                        }
                    }
                }

                hasChildren = false;
                draggedItem.value = null; // 初始化当前拖拽元素内容

                initDrag(); // 销毁当前 sortable 实例并重新创建
            }
        });
    };

    /**
     * @description 获取当前 id 数据所在表格位置索引
     * @param {TableData[]} arr 所遍历的数组
     * @param {string} id 数据 id
     * @return {number} 表格所处索引位置
     */
    const getIndex = (arr: TableData[], id: string | number) => {
        return arr.findIndex(item => item.id === id);
    };

    /**
     * @description  递归查找当前符合条件的数据
     * @param {TableData[]} arr 遍历数据
     * @param {string|number} parentId 匹配 id
     * @return {TableData|null}
     */
    const findDataById = (arr: TableData[], parentId: string | number): TableData | null => {
        for (let i = 0; i < arr.length; i++) {
            if (arr[i].id === parentId) {
                return arr[i];
            } else if (arr[i].children) {
                const result = findDataById(arr[i].children, parentId);
                if (result) {
                    return result;
                }
            }
        }
        return null;
    };

    /**
     * @description 递归设置层级 level
     */
    const recursiveSetLevel = (arr: TableData[], level: number) => {
        if (!isArray(arr)) return;
        arr.forEach((item: TableData) => {
            item.level = level + 1;
            recursiveSetLevel(item.children, item.level);
        });
    };

    return {
        tableKey,
        recordRow,
        initDragInstance
    };
};
